home *** CD-ROM | disk | FTP | other *** search
/ Aminet 5 / Aminet 5 - March 1995.iso / Aminet / comm / tcp / ATCP_src_22.lha / AmiTCP-2.2 / src / amitcp / api / gethostnamadr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-08  |  15.4 KB  |  575 lines

  1. /*
  2.  * $Id: gethostnamadr.c,v 1.7 1993/09/08 14:26:47 too Exp $
  3.  *
  4.  * Last modified: Wed Sep  8 16:50:00 1993 too
  5.  *
  6.  * HISTORY
  7.  * $Log: gethostnamadr.c,v $
  8.  * Revision 1.7  1993/09/08  14:26:47  too
  9.  * Fixed getanswer (from gethostbyaddr) further. Now alias and addr lists
  10.  * are NULL terminated. question is no longer copied. Removed that
  11.  * unnecessary aligment by accident.
  12.  *
  13.  * Revision 1.6  1993/08/20  17:26:34  too
  14.  * Fixed bug in getanswer that caused gethostbyaddr() to return
  15.  * hostname w/ garpage at the end.
  16.  * Added some comments w/ wponders
  17.  * now answer buffer is aligned before host addresses are written.
  18.  * this is unnecessary though.
  19.  * getanswer still writes the question to the answer buffer. This will
  20.  * be fixed later since it doesn't affect functionality
  21.  *
  22.  * Revision 1.5  1993/06/07  12:37:20  too
  23.  * Changed inet_ntoa, netdatabase functions and WaitSelect() use
  24.  * separate buffers for their dynamic buffers
  25.  *
  26.  * Revision 1.4  1993/06/04  11:16:15  jraja
  27.  * Fixes for first public release.
  28.  *
  29.  * Revision 1.3  1993/06/03  20:22:24  too
  30.  * Added variable usens. Fixed some bsd_free memory pointer arguments.
  31.  * Fixed ptr aligment in makehostent
  32.  *
  33.  * Revision 1.2  1993/06/03  07:20:57  too
  34.  * FIxed bugs with pointer arithmetic and destination addressess
  35.  * and data lengths
  36.  *
  37.  * Revision 1.1  1993/06/01  16:35:59  too
  38.  * Initial revision
  39.  *
  40.  *
  41.  */
  42. /*
  43.  * Copyright (c) 1985, 1988 Regents of the University of California.
  44.  * All rights reserved.
  45.  *
  46.  * Redistribution and use in source and binary forms, with or without
  47.  * modification, are permitted provided that the following conditions
  48.  * are met:
  49.  * 1. Redistributions of source code must retain the above copyright
  50.  *    notice, this list of conditions and the following disclaimer.
  51.  * 2. Redistributions in binary form must reproduce the above copyright
  52.  *    notice, this list of conditions and the following disclaimer in the
  53.  *    documentation and/or other materials provided with the distribution.
  54.  * 3. All advertising materials mentioning features or use of this software
  55.  *    must display the following acknowledgement:
  56.  *    This product includes software developed by the University of
  57.  *    California, Berkeley and its contributors.
  58.  * 4. Neither the name of the University nor the names of its contributors
  59.  *    may be used to endorse or promote products derived from this software
  60.  *    without specific prior written permission.
  61.  *
  62.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  63.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  64.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  65.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  66.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  67.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  68.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  69.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  70.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  71.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  72.  * SUCH DAMAGE.
  73.  */
  74.  
  75. #if defined(LIBC_SCCS) && !defined(lint)
  76. static char sccsid[] = "@(#)gethostnamadr.c    6.45 (Berkeley) 2/24/91";
  77. #endif /* LIBC_SCCS and not lint */
  78.  
  79. #include <sys/param.h>
  80. #include <sys/systm.h>
  81. #include <sys/socket.h>
  82. #include <sys/malloc.h>
  83. #include <netinet/in.h>
  84. #include <arpa/inet.h>
  85. #include <netdb.h>
  86. #include <ctype.h>
  87. #include <errno.h>
  88.  
  89. #include <api/arpa_nameser.h>
  90. #include <api/resolv.h>
  91. #include <kern/amiga_includes.h>
  92. #include <api/amiga_api.h>
  93. #include <api/amiga_libcallentry.h>
  94. #include <api/amiga_raf.h>
  95. #include <api/allocdatabuffer.h>     
  96. #include <kern/amiga_subr.h>
  97.  
  98. #include <api/gethtbynamadr.h>     /* prototypes (NO MORE BUGS HERE) */
  99.      
  100. #define    MAXALIASES    35
  101. #define    MAXADDRS    35
  102.  
  103. #if PACKETSZ > 1024
  104. #define    MAXPACKET    PACKETSZ
  105. #else
  106. #define    MAXPACKET    1024
  107. #endif
  108.  
  109. typedef union {
  110.     HEADER hdr;
  111.     u_char buf[MAXPACKET];
  112. } querybuf;
  113.  
  114. typedef union {
  115.     long al;
  116.     char ac;
  117. } align;
  118.  
  119. /*
  120.  * macro for getting error value from another library base function
  121.  * ( which is called directly here )
  122.  */
  123.  
  124. #define errno libPtr->errnoPtr[libPtr->errnoSize - 1]
  125.  
  126. /*
  127.  * hostent structure in SocketBase
  128.  */
  129. #define HOSTENT ((struct hostent *)libPtr->hostents.db_Addr)
  130.  
  131. /*
  132.  * longword align given pointer (i.e. divides by 4)
  133.  */
  134. #define ALIGN(p) (((u_int)(p) + (sizeof(long) - 1)) &~ (sizeof (long) -1))
  135.  
  136. #define MAXALIASES    35
  137. #define MAXADDRS    35  
  138.   
  139. typedef char hostbuf_t[512];
  140.  
  141. struct hoststruct {
  142.   char * host_aliases[MAXALIASES + 1];
  143.   char * h_addr_ptrs[MAXADDRS + 1];
  144.   short host_alias_count;
  145.   short h_addr_count;
  146.   struct hostent host;
  147.   hostbuf_t hostbuf;
  148. };
  149.  
  150. static struct hostent * makehostent(struct SocketBase * libPtr,
  151.                     struct hoststruct * HS,
  152.                     char * ptr);
  153.  
  154. extern int h_errno;
  155. LONG usens = 1;
  156.  
  157. static char *
  158.  getanswer(struct SocketBase * libPtr, querybuf *answer,int anslen, int iquery,
  159.         struct hoststruct * HS)
  160. {
  161.   register HEADER *hp;
  162.   register u_char *cp; /* pointer to traverse in 'answer' */
  163.   register int n;
  164.   u_char *eom;
  165.   int buflen = sizeof HS->hostbuf;
  166.   char *bp; /* bp -- answer buffer pointer */
  167.   int type, class, ancount, qdcount;
  168.   int haveanswer, getclass = C_ANY;
  169.   char **ap, **hap;
  170.   
  171.   eom = answer->buf + anslen;
  172.   /*
  173.    * find first satisfactory answer
  174.    */
  175.   hp = &answer->hdr;
  176.   ancount = ntohs(hp->ancount); /* how many answers returned from nameserver */
  177.   qdcount = ntohs(hp->qdcount); /* how many questions in nameserver query */
  178.  
  179.   /*
  180.    *  bp, points to start of buffer space where new resolved answer is to 
  181.    *  be written. the bp is moved to next free space. Initially it is
  182.    *  set below, to start of buffer allocated for it-
  183.    */
  184.   bp = HS->hostbuf;
  185.   /*
  186.    * address cp to start of nameserver answers (after static sized header)
  187.    */
  188.   cp = answer->buf + sizeof(HEADER);
  189.  
  190.   /*
  191.    * Any questions asked..hmm this should always be the case
  192.    */
  193.   if (qdcount) {
  194. #if 0            /* added by too 8.Sep.1993: skipping strange parts */
  195.     /*
  196.      * gethostbyaddr uses inverse query...
  197.      */
  198.     if (iquery) {
  199.       if ((n = dn_expand((u_char *)answer->buf,
  200.              (u_char *)eom, (u_char *)cp, (u_char *)bp,
  201.              buflen)) < 0) {
  202.     h_errno = NO_RECOVERY;
  203.     return NULL;
  204.       }
  205.       cp += n + QFIXEDSZ;
  206.       /*
  207.        * Hostname in final hostent structure is written here in case
  208.        * of gethostbyaddr. (from question section ???)
  209.        */
  210.       HS->host.h_name = bp;
  211.       n = strlen(bp) + 1;
  212.       bp += n;
  213.       buflen -= n;
  214.     }
  215.     else
  216. #endif    /* 0 */        /* 8Sep93: now code below skips all question strings */
  217.       /*
  218.        * here is normal query (gethostbyname). skipping query section
  219.        * hmm, wondering why is it originally implemented as 2
  220.        * __dn_skipname function calls ?
  221.        */
  222.       cp += __dn_skipname(cp, eom) + QFIXEDSZ;
  223.     while (--qdcount > 0)
  224.       cp += __dn_skipname(cp, eom) + QFIXEDSZ;
  225.   }
  226.   else if (iquery) {
  227.     /*
  228.      * no questions and inverse query :o
  229.      */
  230.     if (hp->aa)
  231.       h_errno = HOST_NOT_FOUND;
  232.     else
  233.       h_errno = TRY_AGAIN;
  234.     return NULL;
  235.   }
  236.   ap = HS->host_aliases;
  237.   HS->host_alias_count = 1; /* there is always NULL as last pointer */
  238.   hap = HS->h_addr_ptrs;
  239.   HS->h_addr_count = 1; /* there is always NULL as last pointer */
  240.   
  241.   haveanswer = 0;
  242.   while (--ancount >= 0 && cp < eom) {
  243.     if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom,
  244.                (u_char *)cp, (u_char *)bp, buflen)) < 0)
  245.       break;
  246.     cp += n;
  247.     /*
  248.      * Type and class are type and class of answer in returned resource
  249.      * record. see arpa[_/]nameserver.h for more information.
  250.      */
  251.     type = _getshort(cp); 
  252.     cp += sizeof(u_short);
  253.     class = _getshort(cp);
  254.     cp += sizeof(u_short) + sizeof(u_long);
  255.     n = _getshort(cp);
  256.     cp += sizeof(u_short);
  257.     
  258.     if (type == T_CNAME) {   /* canonical name (add alias names)*/
  259.       cp += n;
  260.       if (HS->host_alias_count >= MAXALIASES)
  261.     continue;
  262.       *ap++ = bp;
  263.       HS->host_alias_count++;
  264.       n = strlen(bp) + 1;
  265.       bp += n;
  266.       buflen -= n;
  267.       continue;
  268.     }
  269.     if (iquery && type == T_PTR) {  /* domain name pointer (get domain
  270.                        name and return) */
  271.       if ((n = dn_expand((u_char *)answer->buf,
  272.              (u_char *)eom, (u_char *)cp, (u_char *)bp,
  273.              buflen)) < 0) {
  274.     cp += n;
  275.     continue;
  276.       }
  277.       cp += n;
  278.       HS->host.h_name = bp;   /* well, rewrites name pointer if there were
  279.                  returned questions also... */
  280.       haveanswer = 1;
  281.       bp+= (strlen(bp) + 1);
  282.       break;
  283.     }
  284.     if (iquery || type != T_A)  {
  285.       /*
  286.        * here is strange answer from nameserver: inverse query should have
  287.        * been handled earlyer and there should not be any other types
  288.        * left than "host address"
  289.        */
  290. #ifdef RES_DEBUG
  291.       printf("unexpected answer type %d, size %d\n",
  292.          type, n);
  293. #endif
  294.       cp += n;
  295.       continue;
  296.     }
  297.     if (haveanswer) {
  298.       /*
  299.        * Here if one host address answer is already returned (rather odd...)
  300.        */
  301.       if (n != HS->host.h_length) {
  302.     cp += n;
  303.     continue;
  304.       }
  305.       if (class != getclass) {
  306.     cp += n;
  307.     continue;
  308.       }
  309.     }
  310.     else {
  311.       /*
  312.        * Fill in host address data and comparing info for next cycle (if any)
  313.        */
  314.       HS->host.h_length = n;
  315.       getclass = class;
  316.       HS->host.h_addrtype = (class == C_IN) ?
  317.     AF_INET : AF_UNSPEC;
  318.       if (!iquery) {
  319.     /*
  320.      * if not inverse query and haveanswer = 0 host name is first in
  321.      * bp pointed buffer. (rather strange if answer already returned
  322.      * and new addresses are to be added since aren't in that case
  323.      * also names returned or is it inconsistent or have i missed
  324.      * something ?
  325.      */
  326.     int n1;
  327.  
  328.     HS->host.h_name = bp;
  329.     n1 = strlen(bp) + 1;
  330.     bp += n1;
  331.     buflen -= n1;
  332.       }
  333.     }
  334.  
  335. /*    bp = (char *)ALIGN(bp); /* align answer buffer for next host address */
  336.         
  337.     if (HS->host.h_length >= buflen) {
  338. #ifdef RES_DEBUG
  339.       printf("size (%d) too big\n", host->h_length);
  340. #endif
  341.       break;
  342.     }
  343.     /*
  344.      * Fill next host address in address list
  345.      */
  346.     bcopy(cp, *hap++ = bp, n);
  347.     HS->h_addr_count++;
  348.     bp += n;
  349.     buflen -= n;
  350.     cp += n;
  351.     haveanswer++;
  352.   } /* while (--ancount ...) */
  353.   
  354.   if (haveanswer) {
  355.     *ap = NULL;
  356.     *hap = NULL;
  357.     return bp;
  358.   }
  359.   else {
  360.     h_errno = TRY_AGAIN;
  361.     return NULL;
  362.   }
  363. }
  364.  
  365. struct hostent * SAVEDS RAF2 (_gethostbyname,
  366.                   struct SocketBase *,    libPtr,    a6,
  367.                   const char *,        name,    a0)
  368. #if 0
  369. {
  370. #endif  
  371.   querybuf *buf;
  372.   int n;
  373.   char * ptr;
  374.   extern int inet_aton(const char *name, struct in_addr *ia);
  375.   struct hoststruct * HS = NULL;
  376.   struct hostent * anshost = NULL;
  377.   
  378.   CHECK_TASK2();
  379.   
  380.   /*
  381.    * check if name consists only dots and digits.
  382.    */
  383.   if (isdigit(name[0])) {
  384.     struct in_addr inaddr;
  385.     u_long * lptr;
  386.     
  387.     if (!inet_aton(name, &inaddr)) {
  388.       writeErrnoValue(libPtr, 0);
  389.       return NULL;
  390.     }
  391.     
  392.     if (allocDataBuffer(&libPtr->hostents,
  393.             sizeof (struct hostent) + 28) == FALSE) {
  394.       writeErrnoValue(libPtr, ENOMEM);
  395.       return NULL;
  396.     }
  397.     HOSTENT->h_addrtype = AF_INET;
  398.     HOSTENT->h_length = sizeof (struct in_addr);
  399.     lptr = (u_long *)(HOSTENT + 1);
  400.     *lptr++ = inaddr.s_addr;
  401.     *(u_long **)(lptr) = lptr - 1;
  402.     HOSTENT->h_addr_list = (char **)lptr;
  403.     *++lptr = NULL;
  404.     HOSTENT->h_aliases = (char **)lptr;
  405.     HOSTENT->h_name = strcpy((char *)++lptr, name);
  406.     
  407.     return HOSTENT;
  408.   }
  409.   /*
  410.    * Search local database (first) is usens not FIRST
  411.    */
  412.   if (usens != 1)
  413.     if ((anshost =_gethtbyname(libPtr, name)) != NULL || usens == 0)
  414.       return anshost;
  415.   /*
  416.    * Here if usens is FIRST or host not in local database and usens is SECOND
  417.    */
  418.   if ((HS = bsd_malloc(sizeof (querybuf) + sizeof (struct hoststruct),
  419.                M_TEMP, M_WAITOK)) == NULL) {
  420.     writeErrnoValue(libPtr, ENOMEM);
  421.     return NULL;
  422.   }
  423.   buf = (querybuf *)(HS + 1);
  424.   
  425.   ObtainSemaphore(&res_lock);
  426.   n = res_search(libPtr, name, C_IN, T_A, buf->buf, sizeof (querybuf));
  427.   ReleaseSemaphore(&res_lock);
  428.   if (n >= 0) {
  429.     ptr = getanswer(libPtr, buf, n, 0, HS);
  430.     if (ptr != NULL) {
  431.       if ((anshost = makehostent(libPtr, HS, ptr)) != NULL) {
  432.     anshost->h_addrtype = HS->host.h_addrtype;
  433.     anshost->h_length = HS->host.h_length;
  434.       }    
  435.     }
  436.   }
  437.   else {
  438. #ifdef RES_DEBUG
  439.     printf("res_search failed\n");
  440. #endif
  441.     /*
  442.      * If usens is FIRST and host not found using resolver.
  443.      */
  444.     if (usens != 2)
  445.       anshost =_gethtbyname(libPtr, name);
  446.   }
  447.   if (HS)
  448.     bsd_free(HS, M_TEMP);
  449.   return anshost;
  450.   
  451. }
  452.  
  453. struct hostent * SAVEDS RAF4 (_gethostbyaddr,
  454.                   struct SocketBase *,    libPtr,    a6,
  455.                   const char *,        addr,    a0,
  456.                   int,            len,    d0,
  457.                   int,            type,    d1)
  458. #if 0
  459. {
  460. #endif  
  461.   querybuf * buf;
  462.   int n;
  463.   char * ptr;
  464.   struct hoststruct * HS = NULL;
  465.   char * qbuf;
  466.   struct hostent * anshost = NULL;
  467.   
  468.   CHECK_TASK2();
  469.   
  470.   if (type != AF_INET)
  471.     return ((struct hostent *) NULL);
  472.   
  473.   /*
  474.    * Search local database (first) is usens not FIRST
  475.    */
  476.   if (usens != 1)
  477.     if ((anshost =_gethtbyaddr(libPtr, addr, len, type)) != NULL || usens == 0)
  478.       return anshost;
  479.  
  480.   /*
  481.    * Here if usens is FIRST or host not in local database and usens is SECOND
  482.    */
  483.   if ((HS = bsd_malloc(sizeof (querybuf) + MAXDNAME + 1 +
  484.                sizeof (struct hoststruct),  M_TEMP, M_WAITOK))
  485.       == NULL) {
  486.     writeErrnoValue(libPtr, ENOMEM);
  487.     return NULL;
  488.   }
  489.   buf = (querybuf *)(HS + 1);
  490.   qbuf = (caddr_t)(buf + 1);
  491.   
  492.   (void)sprintf(qbuf, "%lu.%lu.%lu.%lu.in-addr.arpa",
  493.         ((unsigned)addr[3] & 0xff),
  494.         ((unsigned)addr[2] & 0xff),
  495.         ((unsigned)addr[1] & 0xff),
  496.         ((unsigned)addr[0] & 0xff));
  497.   ObtainSemaphore(&res_lock);
  498.   n = res_query(libPtr, qbuf, C_IN, T_PTR, (char *)buf, sizeof (querybuf));
  499.   ReleaseSemaphore(&res_lock);
  500.  
  501.   if (n >= 0) {
  502.     ptr = getanswer(libPtr, buf, n, 1, HS);
  503.     if (ptr != NULL) {
  504.       if (HS->h_addr_count == 1) {
  505.     HS->h_addr_count++;
  506.     bcopy(addr, ptr, len);
  507.     HS->h_addr_ptrs[0] = ptr;
  508.     ptr += len;
  509.       }      
  510.       else
  511.     bcopy(addr, &HS->h_addr_ptrs[0], len);
  512.       HS->h_addr_ptrs[1] = NULL;
  513.       if ((anshost = makehostent(libPtr, HS, ptr)) != NULL) {
  514.     anshost->h_addrtype = type;
  515.     anshost->h_length = len;
  516.       }
  517.     }
  518.   }
  519.   else {
  520. #ifdef RES_DEBUG
  521.     printf("res_query failed\n");
  522. #endif
  523.     /*
  524.      * If usens is FIRST and host not found using resolver.
  525.      */
  526.     if (usens != 2)
  527.       anshost = _gethtbyaddr(libPtr, addr, len, type);
  528.   }
  529.   if (HS)
  530.     bsd_free(HS, M_TEMP);
  531.   return anshost;
  532. }
  533.  
  534. static struct hostent * makehostent(struct SocketBase * libPtr,
  535.                     struct hoststruct * HS,
  536.                     char * ptr)
  537. {
  538.   int n, i;
  539.  
  540.   i = (caddr_t)ALIGN(ptr) - (caddr_t)&HS->hostbuf;
  541.   n = i + sizeof (struct hostent) + HS->h_addr_count * sizeof (char *) +
  542.     HS->host_alias_count * sizeof (char *);
  543.     
  544.   if (allocDataBuffer(&libPtr->hostents, n) == FALSE) {
  545.     writeErrnoValue(libPtr, ENOMEM);    
  546.     return NULL;
  547.   }
  548.   /*
  549.    * copy ent data to user buffer (pointers will be set later)
  550.    */
  551.   bcopy(HS->hostbuf, (caddr_t)(HOSTENT + 1), i);
  552.  
  553.   /*
  554.    * how much to add to old pointers
  555.    */
  556.   n = (caddr_t)HOSTENT + sizeof(struct hostent) - (caddr_t)&HS->hostbuf;
  557.   
  558.   /*
  559.    * fill vital fields in user hostent structure
  560.    */
  561.   HOSTENT->h_name = HS->host.h_name + n;
  562.  
  563.   HOSTENT->h_aliases = (char **)((char *)(HOSTENT + 1) + i);
  564.   for (i = 0; HS->host_aliases[i]; i++)
  565.     HOSTENT->h_aliases[i] = HS->host_aliases[i] + n;
  566.   HOSTENT->h_aliases[i++] = NULL;
  567.  
  568.   HOSTENT->h_addr_list = HOSTENT->h_aliases + i;
  569.   for (i = 0; HS->h_addr_ptrs[i]; i++)
  570.     HOSTENT->h_addr_list[i] = HS->h_addr_ptrs[i] + n;
  571.   HOSTENT->h_addr_list[i] = NULL;
  572.  
  573.   return HOSTENT;
  574. }
  575.